package ua.yandex.collections;

public class MyLinkedList implements MyList {
    
    static class Node {
        private Object value;
        private Node next;
    }
    
    private Node root = new Node();
    private int length;
    
    @Override
    public void add(Object e) {
        Object[] temp = {e};
        addAll(temp);
    }
    
    @Override
    public void add(int index, Object e) {
        /*if(index > length) {
            throw new IndexOutOfBoundsException();
        }
        
        Node tempX = root;
        Node tempY;
        //int i = 0;
        for(int i = 0; i != index; i++ ) {
            tempX = tempX.next;
        }
        tempY = new Node();
        tempY.value = new Object();
        tempY.value = e;
        tempY.next = tempX.next;
        tempX = tempY;
        length++;*/
        Object[] temp = {e};
        addAll(index, temp);
    }
    
    @Override
    public void addAll(Object[] c) {
        Node tempX = root;
        Node tempY;
        while (tempX.next != null) {
            tempX = tempX.next;
        }
        for (Object e : c) {
            tempY = new Node();
            //tempY.value = new Object();
            tempY.value = e;
            tempX.next = tempY;
            tempX = tempX.next;
        }
        length += c.length;
        //addAll(length, c);
    }
    
    @Override
    public void addAll(int index, Object[] c) { //numeration from 0
        if (index > length || index < 0) {
            throw new IndexOutOfBoundsException();
        }
        if (index == length) {
            addAll(c);
            return;
        }
        
        Node tempX = root;
        Node tempY;
        for (int i = 0; i != index; i++) {
            tempX = tempX.next;
        }
        for (Object e : c) {
            tempY = new Node();
            //tempY.value = new Object();
            tempY.value = e;
            tempY.next = tempX.next.next;
            tempX.next = tempY;
            tempX = tempX.next;
        }
        length += c.length;
    }
    
    @Override
    public Object get(int index) {
        if (index >= length || index < 0) {
            throw new IndexOutOfBoundsException();
        }
        Node temp = root.next;
        
        for (int i = 0; i < index; i++) {
            temp = temp.next;
        }
        return temp.value;
    }
    
    @Override
    public Object remove(int index) {
        if (index >= length || index < 0) {
            throw new IndexOutOfBoundsException();
        }
        Node temp = root;
        
        for (int i = 0; i != index; i++) {
            temp = temp.next;
        }
        Object value = temp.next.value;
        temp.next = temp.next.next;
        length--;
        return value;
    }
    
    @Override
    public void set(int index, Object e) {
        if (index >= length || index < 0) {
            throw new IndexOutOfBoundsException();
        }
        Node temp = root;
        
        for (int i = 0; i != index; i++) {
            temp = temp.next;
        }
        temp.next.value = e;
    }
    
    @Override
    public int indexOf(Object o) {
        Node temp = root.next;
        if (o != null) {
            for (int i = 0; i < length; i++) {
                if (temp.value.equals(o)) {
                    return i;
                }
                temp = temp.next;
            }
        }
        else {
            for (int i = 0; i < length; i++) {
                if (temp.value == null) {
                    return i;
                }
                temp = temp.next;
            }
        }
        return -1;
    }
    
    @Override
    public int size() {
        return length;
    }
    
    @Override
    public void clear() {
        root.next = null;
        length = 0;
    }
    
    @Override
    public boolean isEmpty() {
        return root.next == null;
    }
    
    @Override
    public Object[] toArray() {
        Node temp = root.next;
        Object[] array = new Object[length];
        for (int i = 0; i < length; i++) {
            array[i] = temp.value;
            temp = temp.next;
        }
        return array;
    }
    
    @Override
    public String toString() {
        //String str = "";
        Node temp = root.next;
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < length - 1; i++) {
            buf.append(temp.value.toString()).append(", ");
            temp = temp.next;
        }
        buf.append(temp.value.toString());
        return buf.toString();
    }
    
    public void addFirst(Object e) {
        add(0, e);
    }
    
    public void addLast(Object e) {
        add(e);
    }
    
    public Object getFirst() {
        return get(0);
    }
    
    public Object getLast() {
        return get(length - 1);
    }
    
    public Object removeFirst() {
        return remove(0);
    }
    
    public Object removeLast() {
        return remove(length - 1);
    }
}